package com.mt.demo.service.impl;

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.mt.demo.manager.MeetingRoomManager;
import com.mt.demo.manager.MeetingUserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class ZombieConnectionCleanupService {
    @Autowired
    private SocketIOServer socketIOServer;

    @Autowired
    private MeetingRoomManager meetingRoomManager;

    @Autowired
    private MeetingUserManager meetingUserManager;

    @Autowired
    private HeartbeatService heartbeatService;

    @Autowired
    private ScreenSharingService screenSharingService;

    private final ConcurrentHashMap<String, Integer> connectionErrorCounts = new ConcurrentHashMap<>();
    private static final int MAX_ERROR_COUNT = 3;
    private static final long CONNECTION_TIMEOUT = 60000; // 60秒

    // 每60秒清理一次僵尸连接
    @Scheduled(fixedRate = 60000)
    public void cleanupZombieConnections() {
        socketIOServer.getAllClients().forEach(client -> {
            String clientId = client.getSessionId().toString();
            String roomId = client.getHandshakeData().getSingleUrlParam("roomId");
            String userId = client.getHandshakeData().getSingleUrlParam("userId");

            if (isZombieConnection(client)) {
                handleZombieConnection(client, roomId, userId);
            }
        });

        // 清理错误计数器中的旧记录
        cleanupErrorCounts();
    }

    // 检查是否是僵尸连接
    private boolean isZombieConnection(SocketIOClient client) {
        String clientId = client.getSessionId().toString();
        
        // 检查心跳状态
        if (!heartbeatService.isClientActive(clientId)) {
            return true;
        }

        // 检查错误计数
        int errorCount = connectionErrorCounts.getOrDefault(clientId, 0);
        if (errorCount >= MAX_ERROR_COUNT) {
            return true;
        }

        // 检查连接状态
        try {
            client.sendEvent("ping");
            return false;
        } catch (Exception e) {
            incrementErrorCount(clientId);
            return true;
        }
    }

    // 处理僵尸连接
    private void handleZombieConnection(SocketIOClient client, String roomId, String userId) {
        // 清理屏幕共享状态
        screenSharingService.cleanupUserScreenSharing(roomId, userId);
        
        // 从房间移除客户端
        meetingRoomManager.removeClientFromRoom(roomId, client);
        
        // 从在线用户列表移除
        meetingUserManager.removeOnlineUser(roomId, userId);
        
        // 通知房间其他用户
        Set<SocketIOClient> roomClients = meetingRoomManager.getRoomClients(roomId);
        roomClients.forEach(roomClient -> {
            if (!roomClient.getSessionId().equals(client.getSessionId())) {
                roomClient.sendEvent("userDisconnected", userId);
            }
        });

        // 清理错误计数
        connectionErrorCounts.remove(client.getSessionId().toString());
        
        // 强制断开连接
        try {
            client.disconnect();
        } catch (Exception e) {
            // 忽略断开连接时的异常
        }
    }

    // 增加错误计数
    public void incrementErrorCount(String clientId) {
        connectionErrorCounts.compute(clientId, (key, count) -> count == null ? 1 : count + 1);
    }

    // 清理错误计数器中的旧记录
    private void cleanupErrorCounts() {
        connectionErrorCounts.entrySet().removeIf(entry -> {
            String clientId = entry.getKey();
            return !isClientConnected(clientId);
        });
    }

    // 检查客户端是否仍然连接
    private boolean isClientConnected(String clientId) {
        return socketIOServer.getAllClients().stream()
                .anyMatch(client -> client.getSessionId().toString().equals(clientId));
    }

    // 重置错误计数
    public void resetErrorCount(String clientId) {
        connectionErrorCounts.remove(clientId);
    }

    // 处理连接错误
    public void handleConnectionError(SocketIOClient client) {
        String clientId = client.getSessionId().toString();
        incrementErrorCount(clientId);
        
        if (connectionErrorCounts.get(clientId) >= MAX_ERROR_COUNT) {
            String roomId = client.getHandshakeData().getSingleUrlParam("roomId");
            String userId = client.getHandshakeData().getSingleUrlParam("userId");
            handleZombieConnection(client, roomId, userId);
        }
    }
}
